package com.grandtech.insurance.common.oss;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.ServiceSignature;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.UploadFileRequest;
import com.aliyun.oss.model.UploadFileResult;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

public class AliOssClientUtils {


    public AliOssClientUtils() {
    }

    /**
     * 获取OSSClient
     *
     * @param aliOssClientParamDO
     */
    private static OSSClient getClient(AliOssClientParamDO aliOssClientParamDO) {
        if (aliOssClientParamDO == null) {
            aliOssClientParamDO = new AliOssClientParamDO();
        }
        if (StringUtils.isBlank(aliOssClientParamDO.getEndpoint())) {
            aliOssClientParamDO.setEndpoint(OssConstant.endpoint);
        }
        if (StringUtils.isBlank(aliOssClientParamDO.getBucketName())) {
            aliOssClientParamDO.setBucketName(OssConstant.bucketName);
        }
        if (StringUtils.isBlank(aliOssClientParamDO.getAccessKeyId())) {
            aliOssClientParamDO.setAccessKeyId(OssConstant.accessKeyId);
        }
        if (StringUtils.isBlank(aliOssClientParamDO.getAccessKeySecret())) {
            aliOssClientParamDO.setAccessKeySecret(OssConstant.accessKeySecret);
        }
        OSSClient ossClient = new OSSClient(aliOssClientParamDO.getEndpoint(), aliOssClientParamDO.getAccessKeyId(),
                aliOssClientParamDO.getAccessKeySecret());
        return ossClient;
    }

    /**
     * 生成key的规则
     *
     * @param filename
     */
    private static String generateRouterKey(String filename) {
        // 年月日文件夹命名
        String[] strNow = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).toString().split("-");
        // 路径加入uuid
        String uuid = UUID.randomUUID().toString();
        // 去掉“-”符号
        uuid = uuid.replaceAll("-", "");
        // 拼接路径
        String path = strNow[0] + "/" + strNow[1] + "/" + strNow[2] + "/" + uuid + "/";
        return path + filename;
    }

    /**
     * 单个文件上传文件
     *
     * @param file
     */
    public static AliOssFileInfoDO uploadFileToAliOss(AliOssClientParamDO aliOssClientParamDO, MultipartFile file) {
        String filename = file.getOriginalFilename();
        String key = OssConstant.filedir + generateRouterKey(filename);
        OSSClient ossClient = null;
        try {
            InputStream inputStream = file.getInputStream();
            ossClient = getClient(aliOssClientParamDO);
            ossClient.putObject(aliOssClientParamDO.getBucketName(), key, inputStream);
            String url = generateUrl(ossClient, aliOssClientParamDO, key);
            AliOssFileInfoDO fileInfo = new AliOssFileInfoDO(filename, key, url, aliOssClientParamDO.getEndpoint(),
                    aliOssClientParamDO.getBucketName());
            return fileInfo;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 单个文件上传文件_验标图片
     *
     * @param file
     */
    public static AliOssFileInfoDO uploadFileToAliOss_yb(AliOssClientParamDO aliOssClientParamDO, File file,
                                                         String key) {
        String filename = file.getName();
        OSSClient ossClient = null;
        try {
            FileInputStream inputStream = new FileInputStream(file);
            ossClient = getClient(aliOssClientParamDO);
            ossClient.putObject(aliOssClientParamDO.getBucketName(), key, inputStream);
            String url = generateUrl(ossClient, aliOssClientParamDO, key);
            AliOssFileInfoDO fileInfo = new AliOssFileInfoDO(filename, key, url, aliOssClientParamDO.getEndpoint(),
                    aliOssClientParamDO.getBucketName());
            return fileInfo;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }


    /**
     * 下载文件
     *
     * @param aliOssClientParamDO
     * @param key
     * @param localPath
     */
    public static void downFile(AliOssClientParamDO aliOssClientParamDO, String key, String localPath) {
        OSSClient ossClient = null;
        try {
            ossClient = getClient(aliOssClientParamDO);
            if (ossClient != null && !key.contains("storage")) {
                // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖，不存在则新建。
                ossClient
                        .getObject(new GetObjectRequest(aliOssClientParamDO.getBucketName(), key), new File(localPath));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 生成签名url
     *
     * @param key
     */
    public static String generateUrl(AliOssClientParamDO aliOssClientParamDO, String key) {
        OSSClient ossClient = null;
        try {
            ossClient = getClient(aliOssClientParamDO);
            return generateUrl(ossClient, aliOssClientParamDO, key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 生成签名url
     *
     * @param ossClient
     * @param key
     */
    public static String generateUrl(OSSClient ossClient, AliOssClientParamDO aliOssClientParamDO, String key) {
        // Long expire = 20 * 1000L;// 20s
        Long expire = 1 * 60 * 60 * 1000L;// 1h
        Date expiration = new Date((new Date()).getTime() + expire);
        URL url = ossClient.generatePresignedUrl(aliOssClientParamDO.getBucketName(), key, expiration);
        String _url = url.toString().replaceAll("http://", "https://");
        return _url;
    }

    /**
     * 生成签名
     *
     * @param s
     */
    public static String computeSignature(String s) {
        try {
            String tosign = URLDecoder.decode(s, "UTF-8");
            System.out.println(tosign);
            String signed = ServiceSignature.create().computeSignature(OssConstant.accessKeySecret, tosign);
            return signed;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 删除单个文件
     *
     * @param aliOssClientParamDO
     * @param key
     * @return true-已删除 false-未删除
     */
    public static boolean deleteObj(AliOssClientParamDO aliOssClientParamDO, String key) {
        boolean doesExist = true;
        OSSClient ossClient = null;
        String bucketName = aliOssClientParamDO.getBucketName();
        try {
            ossClient = getClient(aliOssClientParamDO);
            //删除
            ossClient.deleteObject(bucketName, key);
            //判断key是否存在
            doesExist = ossClient.doesObjectExist(bucketName, key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return doesExist ? false : true;
    }

    /**
     * 判断key是否存在
     *
     * @param aliOssClientParamDO
     * @param key
     */
    public static boolean doesExist(AliOssClientParamDO aliOssClientParamDO, String key) {
        boolean doesExist = true;
        OSSClient ossClient = null;
        String bucketName = aliOssClientParamDO.getBucketName();
        try {
            ossClient = getClient(aliOssClientParamDO);
            //判断key是否存在
            doesExist = ossClient.doesObjectExist(bucketName, key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return doesExist;
    }

    /**
     * 通过断点续传上传文件（适用于文件大于50MB）
     *
     * @param aliOssClientParamDO
     * @param localFilePath       待上传的文件路径
     */
    public static AliOssFileInfoDO partUploadFileToAliOss(AliOssClientParamDO aliOssClientParamDO,
                                                          String localFilePath) {
        long startTime = new Date().getTime();
        AliOssFileInfoDO fileInfo = null;
        OSSClient ossClient = null;
        try {
            String fileName = localFilePath.substring(localFilePath.lastIndexOf(File.separator) + 1);
            String key = OssConstant.filedir + generateRouterKey(fileName);
            // 创建OSSClient实例。
            ossClient = getClient(aliOssClientParamDO);

            ObjectMetadata meta = new ObjectMetadata();
            // 指定上传的内容类型。
            meta.setContentType(getContentType(fileName));
            // 通过UploadFileRequest设置多个参数。
            UploadFileRequest uploadFileRequest = new UploadFileRequest(aliOssClientParamDO.getBucketName(), key);
            // 指定上传的本地文件。
            uploadFileRequest.setUploadFile(localFilePath);
            // 指定上传并发线程数，默认为1。
            uploadFileRequest.setTaskNum(10);
            // 指定上传的分片大小，范围为100KB~5GB，默认为文件大小/10000。
            uploadFileRequest.setPartSize(10 * 1024 * 1024);
            // 开启断点续传，默认关闭。
            uploadFileRequest.setEnableCheckpoint(true);
            // 记录本地分片上传结果的文件。开启断点续传功能时需要设置此参数，上传过程中的进度信息会保存在该文件中，如果某一分片上传失败，再次上传时会根据文件中记录的点继续上传。上传完成后，该文件会被删除。默认与待上传的本地文件同目录，为uploadFile.ucp。
            uploadFileRequest.setCheckpointFile("uploadFile.ucp");
            // 文件的元数据。
            uploadFileRequest.setObjectMetadata(meta);

            // 断点续传上传。
            UploadFileResult uploadFileResult = ossClient.uploadFile(uploadFileRequest);
            if (uploadFileResult != null) {
                String bucketName = uploadFileResult.getMultipartUploadResult().getBucketName();
                String eTag = uploadFileResult.getMultipartUploadResult().getETag();
                String location = uploadFileResult.getMultipartUploadResult().getLocation();
                System.out.println("bucketName: " + bucketName);
                System.out.println("eTag: " + eTag);
                System.out.println("key: " + key);
                System.out.println("location: " + location);
                String url = generateUrl(ossClient, aliOssClientParamDO, key);
                System.out.println("url: " + url);
                fileInfo = new AliOssFileInfoDO(fileName, key, url, ossClient.getEndpoint().toString(), bucketName);
                return fileInfo;
            }
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
            long endTime = new Date().getTime();
            /**
             * 5个线程，分片大小：10M
             * 上传文件大小：196MB
             * 耗时：270000ms
             */
            /**
             * 5个线程，分片大小：20M
             * 上传文件大小：196MB
             * 耗时：215984ms
             */
            /**
             * 10个线程，分片大小：10M
             * 上传文件大小：196MB
             * 耗时：235774ms
             */
            System.out.println("上传文件大小：" + new File(localFilePath).length() / (1024 * 1024) + "MB");
            System.out.println("上传文件大小：" + new File(localFilePath).length() / 1024 + "KB");
            System.out.println("耗时：" + (endTime - startTime) + "ms");
        }

        return fileInfo;
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public static String getContentType(String fileName) {
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));

        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }

        if (".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }

        if (".jpeg".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }

        if (".jpg".equalsIgnoreCase(fileExtension)) {
            return "image/jpg";
        }

        if (".png".equalsIgnoreCase(fileExtension)) {
            return "image/png";
        }

        if (".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }

        if (".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }

        if (".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }

        if (".ppt".equalsIgnoreCase(fileExtension) || ".pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }

        if (".doc".equalsIgnoreCase(fileExtension) || ".docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }

        if (".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }

        if (".zip".equalsIgnoreCase(fileExtension)) {
            return "application/x-zip-compressed";
        }

        if (".rar".equalsIgnoreCase(fileExtension)) {
            return "application/octet-stream";
        }

        if (".xls".equalsIgnoreCase(fileExtension) || ".xlsx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-excel";
        }

        return "application/octet-stream";
    }

    public static void main(String[] args) {
        AliOssClientUtils aliOssClientUtils = new AliOssClientUtils();
        AliOssClientParamDO aliOssClientParamDO = new AliOssClientParamDO();
        aliOssClientParamDO.setEndpoint("https://oss-cn-zhangjiakou.aliyuncs.com");
        aliOssClientParamDO.setAccessKeyId("LTAIP816Jan0Nvjq");
        aliOssClientParamDO.setBucketName("ram-agriinsurance-test");
        aliOssClientParamDO.setAccessKeySecret(OssConstant.accessKeySecret);
        AliOssClientUtils.downFile(aliOssClientParamDO, "2020/01/10/bcf10eabfb1b4e32bf63f2f3b2cd2ca6/TDLZMX.pdf",
                "C:\\Users\\张建春\\Desktop\\tdlzmx.pdf");
//        String  res=generateUrl(aliOssClientParamDO,"mobile/2019/08/06/7b72c9b25a7e48fc9c663374ac7e2d0e/GSD.pdf");
//        System.out.println(res);
//        OSSClient ossClient = new OSSClient(aliOssClientParamDO.getEndpoint(), aliOssClientParamDO.getAccessKeyId(), aliOssClientParamDO.getAccessKeySecret());
//        List<String> keyList = makeKey();
//        for(String key : keyList){
//            aliOssClientUtils.deleteObj(aliOssClientParamDO,key);
//            System.out.println("key: " + key + "  删除完毕");
//        }
//        boolean b = ossClient.doesObjectExist("ram-agriinsurance-prod", "mobile/2019/07/12/a86afa8d4173494f8f53bd5c3724670f/411729101砖店镇.zip");
//        System.out.println(b);
//        System.out.println(generateUrl(ossClient,"mobile/2019/07/22/a4643c56092045e8a3a1d016cbbbe7d9/411503024彭家湾乡.zip"));
//        ossClient.shutdown();
//        new AliOssClientUtils().partUploadFileToAliOss(aliOssClientParamDO,"C:\\Users\\张建春\\Desktop\\test.zip","test.zip");
    }

    public static List<String> makeKey() {
        List<String> keyList = new ArrayList<>();
        keyList.add("mobile/2019/07/22/9c0bd4fe47f74f738df4e86621f46b8a/411729101砖店镇.zip");
        keyList.add("mobile/2019/07/22/282d114635d04fe493e88bc2d412fbc3/411525115石佛店乡.zip");
        keyList.add("mobile/2019/07/22/2ef49bcfaebf49109d88828e7e98d97f/411522101十里镇.zip");
        keyList.add("mobile/2019/07/22/f2c351e6f0734f29a020adce7bdcfb64/620503111石佛镇.zip");
        keyList.add("mobile/2019/07/22/0d4aa32c95fc4bd5ad219d14c7a1a94c/620503102甘泉镇.zip");
        keyList.add("mobile/2019/07/22/6ec9ac69d0404c29b9dfcca5be2b6760/621102112香泉镇.zip");
        keyList.add("mobile/2019/07/22/a4643c56092045e8a3a1d016cbbbe7d9/411503024彭家湾乡.zip");
        keyList.add("mobile/2019/07/23/84f706c0a9d44656b416917b3e614a83/621102112香泉镇.zip");
        keyList.add("mobile/2019/07/23/4ed96896be6f424ba8616b2da3c28fc3/410922213纸房乡.zip");
        keyList.add("mobile/2019/07/23/cee1c3948b6745eb817d6b6d6bc178db/410922103仙庄乡.zip");
        keyList.add("mobile/2019/07/23/ef9c95c7353d42039d04089bc320bc82/410922209固城乡.zip");
        keyList.add("mobile/2019/07/23/e19a7753fc054e14831f6779ae0a7bdc/411729101砖店镇.zip");
        keyList.add("mobile/2019/07/23/9bf148ee46ef4e4c9a59444ab9658fec/411729101砖店镇.zip");
        keyList.add("mobile/2019/07/23/d18e58a1ccb541e4993731331bd0cb41/411729101砖店镇.zip");
        keyList.add("mobile/2019/07/24/e70fea2a6e3e48a9b99bc5f7809f4a10/411729101砖店镇.zip");
        return keyList;
    }
}
